<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>仓库失火自动报警灭火系统监控中心</title>
<style>
  body {
    margin:0; font-family:"Microsoft YaHei",sans-serif;
    background:linear-gradient(180deg,#0a1f3d,#051225);
    color:#e6f4ff;
  }
  header {
    background:#0c2f5c; padding:12px 24px;
    display:flex; justify-content:space-between; align-items:center;
    color:#fff; font-size:20px; font-weight:600;
  }
  .time { font-size:14px; color:#9dd1ff; }
  .layout {
    display:grid; grid-template-columns:260px 1fr 260px;
    gap:12px; padding:12px;
  }
  .card {
    background:rgba(0,40,80,0.6);
    border-radius:8px;
    padding:12px;
    box-shadow:0 0 10px rgba(0,0,0,0.5) inset;
  }
  .card h3 {
    margin:0 0 10px; font-size:16px; color:#4dc3ff;
    border-left:3px solid #4dc3ff; padding-left:8px;
  }
  .status-item {
    margin:6px 0; display:flex; justify-content:space-between;
  }
  .status-ok { color:#4dff88; }
  .status-bad { color:#ff5555; }
  .grid { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
  .region {
    background:rgba(0,30,60,0.8);
    border-radius:6px; padding:20px; text-align:center;
  }
  .region span {
    display:inline-block; margin:6px; padding:12px;
    background:#00cc88; border-radius:50%; color:#fff;
  }
  .stat-box { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  .stat {
    background:#002b55; border-radius:6px; padding:12px;
    text-align:center; font-size:14px;
  }
  .stat strong { display:block; font-size:18px; color:#4dc3ff; }
  .btns { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-top:10px; }
  .btn {
    padding:12px; border-radius:6px; text-align:center; cursor:pointer;
    background:#004488; color:#fff; font-weight:600;
  }
  .btn.stop { background:#cc2222; }
  .log { font-size:13px; background:#001b33; padding:10px; border-radius:6px; max-height:200px; overflow:auto; }

  /* 左下角弹窗容器 */
  .toast-container {
    position:fixed; left:20px; bottom:20px;
    display:flex; flex-direction:column;
    gap:10px; z-index:9999;
  }
  .toast {
    min-width:220px; max-width:320px;
    padding:14px 16px; border-radius:8px;
    font-weight:600; color:#fff;
    box-shadow:0 4px 12px rgba(0,0,0,0.4);
    opacity:0; transform:translateY(10px);
    animation:fadeIn .2s forwards;
  }
  @keyframes fadeIn { to {opacity:1; transform:translateY(0);} }
  .toast.fire { background:linear-gradient(90deg,#ff3b3b,#ff6a6a); }
  .toast.fire.old { background:#663333; color:#ffaaaa; }
  .toast.nofire { background:linear-gradient(90deg,#28a745,#5cd65c); }
</style>
</head>
<body>
<header>
  <div>仓库失火自动报警灭火系统监控中心</div>
  <div class="time" id="time"></div>
</header>

<div class="layout">
  <!-- 左侧 -->
  <div>
    <div class="card">
      <h3>系统状态总览</h3>
      <div class="status-item"><span>系统状态</span><span class="status-ok">正常</span></div>
      <div class="status-item"><span>平均温度</span><span>25.4℃</span></div>
      <div class="status-item"><span>湿度</span><span>2.5%</span></div>
      <div class="status-item"><span>灭火泵压力</span><span>1.2MPa</span></div>
    </div>
    <div class="card" style="margin-top:12px;">
      <h3>报警记录</h3>
      <div class="log" id="log"></div>
    </div>
  </div>

  <!-- 中间 -->
  <div class="card">
    <h3>仓库平面监控图</h3>
    <div class="grid">
      <div class="region">A区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">B区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">C区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">D区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">E区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">F区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">G区域<br><span>传感</span><span>摄像</span></div>
      <div class="region">H区域<br><span>传感</span><span>摄像</span></div>
    </div>
  </div>

  <!-- 右侧 -->
  <div>
    <div class="card">
      <h3>设备状态</h3>
      <div class="status-item"><span>主控器</span><span class="status-ok">正常运行</span></div>
      <div class="status-item"><span>通信模块</span><span>信号良好</span></div>
      <div class="status-item"><span>备用电源</span><span>100%</span></div>
      <div class="status-item"><span>水泵系统</span><span>待机</span></div>
    </div>
    <div class="card" style="margin-top:12px;">
      <h3>统计信息</h3>
      <div class="stat-box">
        <div class="stat"><strong>156</strong>传感器数</div>
        <div class="stat"><strong>24</strong>喷淋头数</div>
        <div class="stat"><strong id="fireCount">0</strong>火警次数</div>
        <div class="stat"><strong id="nofireCount">0</strong>解除次数</div>
      </div>
    </div>
    <div class="card" style="margin-top:12px;">
      <h3>快捷操作</h3>
      <div class="btns">
        <div class="btn">系统自检</div>
        <div class="btn stop">紧急停止</div>
        <div class="btn">重启</div>
        <div class="btn">生成报告</div>
      </div>
    </div>
  </div>
</div>

<!-- 弹窗容器 -->
<div id="toasts" class="toast-container"></div>

<!-- MQTT.js -->
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script>
  const logEl=document.getElementById("log")
  const toastContainer=document.getElementById("toasts")
  const fireCountEl=document.getElementById("fireCount")
  const nofireCountEl=document.getElementById("nofireCount")
  const TOPIC="warehouse/alarm"
  let client=null
  let fireCount=0, nofireCount=0

  function log(msg){
    const t=new Date().toLocaleTimeString()
    logEl.insertAdjacentHTML("afterbegin",`<div>[${t}] ${msg}</div>`)
  }

  function connect(){
    const url="ws://broker.emqx.io:8083/mqtt"
    const clientId="web-"+Math.random().toString(16).slice(2,8)
    client=mqtt.connect(url,{clientId})
    client.on("connect",()=>{ log("已连接 "+url); client.subscribe(TOPIC) })
    client.on("message",(topic,payload)=>{
      const msg=payload.toString().trim()
      log(`收到 ${topic}: ${msg}`)
      handleMsg(msg)
    })
  }

  function handleMsg(msg){
    if(msg.toLowerCase()==="fire"){ addFireToast() }
    else if(msg.toLowerCase()==="nofire"){ clearFireToasts(); addNoFireToast() }
  }

  function addFireToast(){
    // 让已有 fire 变 old
    toastContainer.querySelectorAll(".toast.fire").forEach(t=>{
      if(!t.classList.contains("old")){
        t.classList.add("old")
        setTimeout(()=>t.remove(),5000)
      }
    })
    // 新 fire 放最下面
    const toast=document.createElement("div")
    toast.className="toast fire"
    toast.textContent="🔥 火警!"
    toastContainer.appendChild(toast)

    fireCount++
    fireCountEl.textContent=fireCount
  }

  function clearFireToasts(){
    toastContainer.querySelectorAll(".toast.fire").forEach(t=>t.remove())
  }

  function addNoFireToast(){
    // 清除已有 nofire 弹窗
    toastContainer.querySelectorAll(".toast.nofire").forEach(t => t.remove())

    // 添加新的 nofire 弹窗
    const toast = document.createElement("div")
    toast.className = "toast nofire"
    toast.textContent = "✅ 安全 (No Fire)"
    toastContainer.appendChild(toast)
    setTimeout(() => toast.remove(), 10000)

    nofireCount++
    nofireCountEl.textContent = nofireCount
  }

  // 时间刷新
  function updateTime(){
    const now=new Date()
    document.getElementById("time").textContent=
      now.getFullYear()+"/"+(now.getMonth()+1)+"/"+now.getDate()+" "+
      now.toLocaleTimeString()
  }
  setInterval(updateTime,1000); updateTime()

  window.addEventListener("load",connect)
  window.addEventListener("beforeunload",()=>{ if(client) client.end(true) })
</script>
</body>
</html>
